跳到主要内容

SpringCloud 整合 Zookeeper

使用 Zookeeper 做服务注册中心

配置环境

<!-- 注意,使用的是 2.3.4.RELEASE 版本的 SpringBoot -->
<!--引入zk-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
</dependency>

配置服务生产者

# 服务别名----注册zookeeper到注册中心名称
spring:
application:
name: "payment-service"
cloud:
zookeeper:
connect-string: 127.0.0.1:2181 # zookeeper 的服务地址
@SpringBootApplication
@EnableDiscoveryClient
public class Payment03 {
public static void main(String[] args) {
SpringApplication.run(Payment03.class, args);
}
}

注意这里的 @EnableDiscoveryClient 注解可加可不加,Spring Cloud E 版本之后就不需要再写 @EnableDiscoveryClient 注解了,直接导入依赖,配置一下 application.yml文件即可,只不过显示的注明这里启用了服务发现会直观一点

随便写一个 Controller 测试

@Slf4j
@RestController
public class PaymentController {
@Value("${server.port}")
private String serverPort;

@GetMapping(value = "/payment/zk")
public String paymentzk() {
return "spring cloud with zookeeper:" + serverPort + "\t" + UUID.randomUUID().toString();
}
}

启动时会发现,开始时就报错了,经排查发现是版本问题

检查 ZK 的版本,发现它是 3.6.2

而上面 2.3.4.RELEASE 版本的 SpringBoot 内置的 spring-cloud-starter-zookeeper-discovery 使用的 zookeeper 连接用的客户端才 3.5.3-beta(通过 Maven 类图找到这个依赖的)

所以需要手动替换一下这个依赖(可以使用 IDEA 的 Maven 类图工具)

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
<exclusions>
<exclusion>
<artifactId>zookeeper</artifactId>
<groupId>org.apache.zookeeper</groupId>
</exclusion>
</exclusions>
</dependency>

<!-- https://mvnrepository.com/artifact/org.apache.zookeeper/zookeeper -->
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.6.2</version>
</dependency>

但是启动时发现又一堆报错

回想一下之前学习 ZK 时知道因为 zookeeper 这个包依赖 log4j,如果没有添加配置会抛出错误,而到了 Spring 这里,它内置了日志框架,所以这里再将 zookeeper 包内的日志框架进行排除

修改上面的 zookeeper 依赖

<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.6.2</version>
<exclusions>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>

检查数据

运行前 先检查一下 ZK,可以发现里面没有任何的节点(这个 Zookeeper 节点是自带的,不用管他)

再次运行时发现多了个 services

然后进去看可以发现当前服务已经被注册进去了

它的内容存储在光标指向的位置

打印它的数据,可以发现这个节点里面存了服务相关的数据

格式化一下这个 json 串

{
"name": "payment-service",
"id": "1246ea3d-07f1-41b4-837e-43a84efa1caa",
"address": "localhost",
"port": 8004,
"sslPort": null,
"payload": {
"@class": "org.springframework.cloud.zookeeper.discovery.ZookeeperInstance",
"id": "application-1",
"name": "payment-service",
"metadata": {
"instance_status": "UP"
}
},
"registrationTimeUTC": 1617443623258,
"serviceType": "DYNAMIC",
"uriSpec": {
"parts": [{
"value": "scheme",
"variable": true
}, {
"value": "://",
"variable": false
}, {
"value": "address",
"variable": true
}, {
"value": ":",
"variable": false
}, {
"value": "port",
"variable": true
}]
}
}

注意,这个节点是临时节点,它会在注册进来的服务挂掉一段时间后(一直发心跳没人回)将其删掉

如果再次重新注册一次这个服务,Zookeeper 又会再次创建一个

配置服务消费者

消费者的 Maven 配置和上面是一样的

# 服务别名----注册zookeeper到注册中心名称
spring:
application:
name: "consumer-order"
cloud:
zookeeper:
connect-string: 127.0.0.1:2181 # zookeeper 的服务地址

在启动类里面把 RestTemplate 注册进来

@SpringBootApplication
public class ConsumerOrderZk8080Application {

@Bean
@LoadBalanced // 这个 @LoadBalanced 注解让 RestTemplate 拥有负载均衡
public RestTemplate getRestTemplate(){
return new RestTemplate();
}

public static void main(String[] args) {
SpringApplication.run(ConsumerOrderZk8080Application.class, args);
}

}

这里 INVOKE_URL 就是上面生产者的名称

@RestController
@Slf4j
public class OrderZKController {
public static final String INVOKE_URL = "http://payment-service";

@Resource
private RestTemplate restTemplate;

@GetMapping(value = "/consumer/payment/zk")
public String paymentInfo() {
return restTemplate.getForObject(INVOKE_URL + "/payment/zk", String.class);
}
}